#ifndef CELL_H
#define CELL_H

#include "../../base.h"
#include "../../test/UnitTest.h"
#include "../../ai/ga/cpm/EmbryoGenome.h"
using GA::EmbryoGenome;

/* CellId */
typedef uint16 CellId;

/* CellId max value */
#define CELLID_MAX 0xffff

#define ADHESION_KEY_LOCK_SIZE 4

class CellController;
class PhysicsParameters;
class World;

//TODO
// - behaviours : death, divide
class Cell {
	UNIT_TEST
public:
	/* static ctors */
	static Cell** newCellCheckers(World& world, int xPosition, int yPosition, int width, int height, int side);
	static Cell*  newCellSquare(  World& world, int xPosition, int yPosition, int side);

	/* ctor */
	Cell(World& world, int currentSize);

	/* dtor */
	~Cell();

	/* set controller */
	void setController(CellController* controller);

	/* Id */
	CellId getId() const;

	/* update (includes controller update) */
	void update();

	/* energies */
	double getEnergy(         PhysicsParameters const& parameters, int xPosition, int yPosition) const; /* current        */
	double getEnergyIfAdded(  PhysicsParameters const& parameters, int xPosition, int yPosition) const; /* if added one   */
	double getEnergyIfRemoved(PhysicsParameters const& parameters, int xPosition, int yPosition) const; /* if removed one */

	/* size */
	void shrink();
	void grow();

	/* target size */
	void setTargetSize(int target);

	/* membrane rigidity */
	void setMembraneRigidity(double rigidity);

	/* adhesion */
	void setAdhesionKeyLock(int key, int lock);
	double getAdhesionToSubstrate() const;
	double getAdhesionToCell(Cell const& cell) const;

private:
	World&          _world;        /* world      */
	CellId          _id;           /* id         */
	CellController* _controller;   /* controller */

	int _size;
	int _targetSize;

	double _membraneRigidity;

	int _adhesionKey;
	int _adhesionLock;

	double _getNeighbours(int xPosition, int yPosition) const;
	double _membraneGetSumOur(int xPosition, int yPosition) const;
	double _membraneGetSumOther(int xPosition, int yPosition) const;
};

#endif	// CELL_H

